﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_STATIC_STRING_H
#define _UXS_STATIC_STRING_H

#pragma once

#include "TString.h"

namespace UX_STL
{
namespace UXTypes
{

	#define RET_ERROR( _ret )	{ WARNING("error in static string");  return _ret; }
	#define RET_FALSE			RET_ERROR( false )
	#define RET_VOID			RET_ERROR( ; )



	//
	// Static String
	//

	template < typename T, usize C, typename S = TFastCopyStrategy<T> >
	struct TStaticString
	{
	// types
	public:
		STATIC_ASSERT( C > 1, "invalid string size" );

		typedef TStaticString<T,C,S>	Self;
		typedef S						Strategy;
		typedef T						value_t;
		typedef uni_array<T>			uni_arr;
		typedef uni_array<const T>		uni_c_arr;
		typedef TUniString<T>			uni_str;
		typedef TUniString<const T>		uni_cstr;


	// variables
	private:
		T		_pMemory[C];
		usize	_uLength;


	// methods
	private:
		static usize _GetLength (const void *pBegin, const void *pEnd);

	public:
		TStaticString ();

		explicit
		TStaticString (const uni_cstr &s);

		explicit
		TStaticString (const T * const pStr);

		TStaticString (const T * const pStr, usize uLength);

		TStaticString (const Self &s);
		
		// копирует строку
		template <typename B>
		void Copy (const TUniString<const B> &sStr);
		void Copy (const uni_cstr &sStr);

		// копирует в статичную строку
		template <usize I>
		void CopyTo (T (&tArr)[I]) const;

		// очищает строку
		void Clear ();
		void ClearMem ();
		
		// при совпадении зменяет символ
		void ChangeChars (const T tFromChar, const T tToChar);

		// удалить символы
		void CutChars (const T tChar);
		
		// удаляет uCount символов
		void Erase (usize uPos, usize uCount = 1);

		// пустой ли?
		bool Empty ()	const												{ return _uLength == 0; }
		
		// ищет строку и возвращает позицию
		bool Find (const uni_cstr &sStr, OUT usize &uPos, usize uStart = 0)	const	{ return uni_cstr(*this).Find( sStr, uPos, uStart ); }
		bool Find (const T tElem, OUT usize &uPos, usize uStart = 0)		const	{ return uni_cstr(*this).Find( tElem, uPos, uStart ); }
		
		// ищет строку без учета регистра и возвращает позицию
		bool FindI (const uni_cstr &sStr, OUT usize &uPos, usize uStart = 0)const	{ return uni_cstr(*this).FindI( sStr, uPos, uStart ); }
		bool FindI (const T tElem, OUT usize &uPos, usize uStart = 0)		const	{ return uni_cstr(*this).FindI( tElem, uPos, uStart ); }

		// устанавливает размер строки
		void SetLength (usize uLength);

		// удаляет последний символ
		void PopBack ();

		// преобразовать в динамическу строку
		template <typename T2, typename S2, typename A2>
		void ToDynamic (OUT TString<T2,S2,A2> &sArr) const;

		usize GetIndex (const T &elem)							const	{ return uni_c_arr(*this).GetIndex( elem ); }

		T			*	ptr ()											{ return _pMemory; }
		const T		*	ptr ()									const	{ return _pMemory; }
		const T		*	cstr ()									const	{ return _pMemory; }
		usize			Count ()								const	{ return _uLength+1; }
		usize			Length ()								const	{ return _uLength; }
		usize			Size ()									const	{ return sizeof(T)*Count(); }
		usize			Capacity ()								const	{ return C; }
		usize			FullSize ()								const	{ return sizeof(_pMemory); }

		T			*	Begin ()										{ return _pMemory; }
		T const		*	Begin ()								const	{ return _pMemory; }
		T			*	End ()											{ return _pMemory + Length(); }
		T const		*	End ()									const	{ return _pMemory + Length(); }

		bool			operator !  ()							const	{ return not Empty(); }
		
		operator		uni_arr ()										{ return uni_arr( _pMemory, Length()+1 ); }
		operator const	uni_c_arr () const								{ return uni_c_arr( _pMemory, Length()+1 ); }

		operator		uni_str ()										{ return uni_str( _pMemory, Length() ); }
		operator const	uni_cstr () const								{ return uni_cstr( _pMemory, Length() ); }

		T			&	operator [] (usize i);
		const T		&	operator [] (usize i)					const;

		Self &			operator =  (const T * const pStr)				{ Copy(pStr);	return *this; }
		Self &			operator =  (const uni_cstr &sStr)				{ Copy(sStr);	return *this; }

		bool			operator == (const uni_cstr &sStr)		const	{ return uni_cstr(*this) == sStr; }
		bool			operator == (const T * const pStr)		const	{ return uni_cstr(*this) == pStr; }

		bool			operator != (const uni_cstr &sStr)		const	{ return not ( *this == sStr ); }
		bool			operator != (const T * const pStr)		const	{ return not ( *this == pStr ); }
		
		bool			operator < (const uni_cstr &sStr)		const	{ return uni_cstr(*this) < sStr; }
		bool			operator > (const uni_cstr &sStr)		const	{ return uni_cstr(*this) > sStr; }

		bool			NumStrLess (const uni_cstr &sStr)		const	{ return uni_cstr(*this).NumStrLess( sStr ); }
	};



	template <usize I>
	struct static_string : TStaticString< char, I >
	{
		static_string () {}
		static_string (const char * const pStr) : TStaticString<char,I>( pStr ) {}
		static_string (const char * const pStr, usize uLength): TStaticString<char,I>( pStr, uLength ) {}
		static_string (const uni_string &str)	{ TStaticString< char, I >::Copy( (uni_c_string) str ); }
		static_string (uni_c_string str)		{ TStaticString< char, I >::Copy( str ); }
	};


	template <usize I>
	struct static_wstring : TStaticString< wchar, I >
	{
		static_wstring () {}
		static_wstring (const wchar * const pStr) : TStaticString<wchar,I>( pStr ) {}
		static_wstring (const wchar * const pStr, usize uLength): TStaticString<wchar,I>( pStr, uLength ) {}
		static_wstring (const uni_wstring &str)		{ TStaticString< wchar, I >::Copy( (uni_c_wstring) str ); }
		static_wstring (const uni_c_wstring &str)	{ TStaticString< wchar, I >::Copy( str ); }
	};


	// TString conversion
	template <typename T, typename S, typename A>
	template <usize I>
	inline TString<T,S,A>::TString (const TStaticString<T,I,S> &sStr): _pMemory((T*)_s_aEmpty), _uCount(1), _uSize(1)
	{
		Copy( sStr );
	}


	// TStaticString methods
	template <typename T, usize C, typename S>
	inline TStaticString<T,C,S>::TStaticString (): _uLength(0)
	{
		_pMemory[0] = 0;
	}
	
	template <typename T, usize C, typename S>
	inline TStaticString<T,C,S>::TStaticString (const Self &s): _uLength(s._uLength)
	{
		MemCopy( _pMemory, s._pMemory, sizeof(_pMemory) );
	}
	
	template <typename T, usize C, typename S>
	inline TStaticString<T,C,S>::TStaticString (const T * const pStr): _uLength(0)
	{
		Copy( uni_cstr( pStr ) );
	}

	template <typename T, usize C, typename S>
	inline TStaticString<T,C,S>::TStaticString (const T * const pStr, usize uLength): _uLength(0)
	{
		Copy( uni_cstr( pStr, uLength ) );
	}
		

	template <typename T, usize C, typename S>
	inline TStaticString<T,C,S>::TStaticString (const uni_cstr &sStr): _uLength(0)
	{
		Copy( sStr );
	}

	
	template <typename T, usize C, typename S>
	inline usize TStaticString<T,C,S>::_GetLength (const void *pBegin, const void *pEnd)
	{
		ASSERT( pBegin <= pEnd );
		return ( usize(pEnd) - usize(pBegin) ) / sizeof(T);
	}

		
	template <typename T, usize C, typename S>
	template <typename B>
	inline void TStaticString<T,C,S>::Copy (const TUniString<const B> &sStr)
	{
		if ( sStr.Empty() or (void *)sStr.ptr() == (void *)_pMemory ) {
			Clear();
			return;
		}

		ASSERT( sStr.Length() < Capacity() );
		const usize	_uLength = Min( sStr.Length(), Capacity()-1 );

		for (usize i = 0; i < _uLength; ++i) {
			_pMemory[i] = (T)sStr[i];
		}
		_pMemory[_uLength] = 0;
	}

		
	template <typename T, usize C, typename S>
	inline void TStaticString<T,C,S>::Copy (const uni_cstr &sStr)
	{
		if ( sStr.Empty() or sStr.ptr() == _pMemory ) {
			Clear();
			return;
		}
		
		ASSERT( sStr.Length() < Capacity() );
		_uLength = UXMath::Min( sStr.Length(), Capacity()-1 );
		
		Strategy::Copy( _pMemory, sStr.ptr(), _uLength );
		_pMemory[_uLength] = 0;
	}
	
		
	template <typename T, usize C, typename S>
	template <usize I>
	inline void TStaticString<T,C,S>::CopyTo (T (&tArr)[I]) const
	{
		const usize	u_len = UXMath::Min( I, C )-1;

		for (usize i = 0; i < u_len; ++i)
			tArr[i] = _pMemory[i];

		tArr[u_len] = 0;
	}

		
	template <typename T, usize C, typename S>
	inline void TStaticString<T,C,S>::Clear ()
	{
		ClearMem();
	}

		
	template <typename T, usize C, typename S>
	inline void TStaticString<T,C,S>::ClearMem ()
	{
		_uLength = 0;
		_pMemory[0] = 0;
	}
		
		
	template <typename T, usize C, typename S>
	inline void TStaticString<T,C,S>::ChangeChars (const T tFromChar, const T tToChar)
	{
		if ( tFromChar == 0 or tToChar == 0 )
			RET_VOID;

		for (usize i = 0; i < Length(); ++i)
		{
			if ( _pMemory[i] == tFromChar )
				_pMemory[i] = tToChar;
		}
	}

		
	template <typename T, usize C, typename S>
	inline void TStaticString<T,C,S>::CutChars (const T tChar)
	{
		for (usize i = 0; i < Length(); ++i)
		{
			if ( _pMemory[i] == tChar )
			{
				Erase( i );
				--i;
			}
		}
	}
		
		
	template <typename T, usize C, typename S>
	inline void TStaticString<T,C,S>::Erase (usize uPos, usize uCount)
	{
		if ( uPos >= Length() or uCount == 0 )
			RET_VOID;
		
		if ( uPos + uCount >= Capacity() )
			uCount = Capacity() - uPos;

		_uLength -= uCount;

		const usize	u_len = _uLength + 1 - uPos;

		for (usize i = 0; i < u_len; ++i) {
			Strategy::Replace( _pMemory + uPos + i, _pMemory[uPos + uCount + i] );
		}
	}
	
	
	template <typename T, usize C, typename S>
	inline void TStaticString<T,C,S>::SetLength (usize uLength)
	{
		if ( uLength >= Capacity() )
			RET_VOID;

		_uLength = uLength;
		_pMemory[_uLength] = 0;
	}

	
	template <typename T, usize C, typename S>
	inline void TStaticString<T,C,S>::PopBack ()
	{
		if ( Length() == 0 )
			RET_VOID;

		_pMemory[ --_uLength ] = 0;
	}

	
	template <typename T, usize C, typename S>
	template <typename T2, typename S2, typename A2>
	inline void TStaticString<T,C,S>::ToDynamic (TString<T2,S2,A2> &sStr) const
	{
		sStr.Copy( ptr(), Length() );
	}
		
		
	template <typename T, usize C, typename S>
	inline T & TStaticString<T,C,S>::operator [] (usize i)
	{
		ASSERT( i <= Length() );
		return _pMemory[i];
	}

		
	template <typename T, usize C, typename S>
	inline const T & TStaticString<T,C,S>::operator [] (usize i) const
	{
		ASSERT( i <= Length() );
		return _pMemory[i];
	}

	
	#undef  RET_ERROR
	#undef	RET_FALSE
	#undef  RET_VOID

//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_STATIC_STRING_H